﻿using System;
using System.Windows.Data;
using System.Windows.Media.Effects;
using Red.Controls.Diagrams.ViewModels;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Red.Controls.Diagrams
{
    public class LODVisibilityConverter : IValueConverter
    {
        public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            var currentLOD = ( DiagramLOD )value;
            var lodToCheck = ( DiagramLOD )parameter;

            return currentLOD >= lodToCheck ? Visibility.Hidden : Visibility.Visible;
        }

        public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            return value;
        }
    }

    public class LODEffectConverter : IValueConverter
    {
        public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            var currentLOD = ( DiagramLOD )value;
            var lodToCheck = ( DiagramLOD )parameter;

            return currentLOD >= lodToCheck ? null : new DropShadowEffect { BlurRadius = 0 };
        }

        public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            return value;
        }
    }

    public class LODCurvedArrowConverter : IValueConverter
    {
        public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            var currentLOD = ( DiagramLOD )value;
            var lodToCheck = ( DiagramLOD )parameter;

            return currentLOD >= lodToCheck;
        }

        public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
        {
            return value;
        }
    }

    partial class DiagramStyles : ResourceDictionary
    {
        /// <summary>
        /// Event raised when the size of a node has changed.
        /// </summary>
        private void Node_SizeChanged( object sender, SizeChangedEventArgs e )
        {
            //
            // The size of a node, as determined in the UI by the node's data-template,
            // has changed.  Push the size of the node through to the view-model.
            //
            var element = ( FrameworkElement )sender;
            var node = ( NodeViewModel )element.DataContext;
            node.Size = new Size( element.ActualWidth, element.ActualHeight );            
        }

        private void ShowConnectorContextMenu_CanExecute( object sender, CanExecuteRoutedEventArgs e )
        {
            var contextMenuItems = e.Parameter as List<ConnectorMenuItem>;
            e.CanExecute = contextMenuItems.Count != 0;
        }

        private void ShowConnectorContextMenu_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            var contextMenuItems = e.Parameter as List<ConnectorMenuItem>;

            var contextmenu = this[ "ConnectorContextMenu" ] as ContextMenu;
            contextmenu.ItemsSource = contextMenuItems;
            contextmenu.IsOpen = true;
            contextmenu.PlacementTarget = sender as UIElement;
            e.Handled = true;
        }

        private void Node_DragEnter( object sender, DragEventArgs e )
        {
            var element = sender as FrameworkElement;
            var node = element.DataContext as NodeViewModel;

            if ( node.AcceptsDraggedData( e.Data ) )
            {
                // TODO: add some fancy effects here?
            }
        }

        /// <summary>
        /// For ability to reject dragged data.
        /// </summary>
        private void Node_DragOver( object sender, DragEventArgs e )
        {
            var element = sender as FrameworkElement;
            var node = element.DataContext as NodeViewModel;

            // NOTE: DragOver is called whole time when drag is over the control, so this can be optimized or methods called inside should be light.
            if ( node.AcceptsDraggedData( e.Data ) == false )
                e.Effects = DragDropEffects.None;
        }

        private void Node_DragLeave( object sender, DragEventArgs e )
        {
            var element = sender as FrameworkElement;
            var node = element.DataContext as NodeViewModel;

            // TODO: implement turning off some fancy effects here?
        }

        private void Node_Drop( object sender, DragEventArgs e )
        {
            var element = sender as FrameworkElement;
            var node = element.DataContext as NodeViewModel;

            if ( node.AcceptsDraggedData( e.Data ) )
            {
                node.DropDraggedData( e.Data );
            }
        }
    }

    class ConnectorMenuItemTemplateSelector : ItemContainerTemplateSelector
    {
        public override DataTemplate SelectTemplate( object item, ItemsControl parentItemsControl )
        {
            if ( item is RemoveConnectionMenuItem )
                return parentItemsControl.Resources[ "RemoveConnectionMenuItemStyle" ] as DataTemplate;

            if ( item is RemoveAttachedConnectionsMenuItem )
                return parentItemsControl.Resources[ "RemoveAttachedConnectionsMenuItemStyle" ] as DataTemplate;

            if ( item is SeparatorMenuItem )
                return parentItemsControl.Resources[ "SeparatorMenuItemStyle" ] as DataTemplate;

            if ( item is RemoveDummyConnectorMenuItem )
                return parentItemsControl.Resources[ "RemoveDummyConnectorMenuItem" ] as DataTemplate;

            return null;
        }
    }
}
